---
slug: /features/shell
description: "Iterate faster with familiar Bash-like syntax and autocomplete"
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import VideoPlayer from '../../src/components/VideoPlayer';

# Interactive Shell

The Dagger CLI includes an interactive shell that translates the familiar Bash syntax to Dagger API requests.
It's the simplest and fastest way to run Dagger workflows directly from the command-line.

You can use it for builds, tests, ephemeral environments, deployments, or any other task you want to automate from the terminal.

## Sandboxing

Dagger Shell commands run as sandboxed functions, accessing host resources (files, secrets, services) only when explicitly provided as arguments.
This can make commands slightly more verbose, but also more repeatable, giving you confidence to iterate quickly without second-guessing.

### Example

Here's an example of Dagger Shell in action:

```shell
container | from alpine | with-exec apk add curl | with-exec -- curl -L https://dagger.io | stdout
```

<VideoPlayer src="/img/current_docs/features/shell-curl.webm" alt="Dagger Shell" />

Here's another, more complex example:

```shell
container |
  from cgr.dev/chainguard/wolfi-base |
  with-exec apk add go |
  with-directory /src https://github.com/golang/example#master |
  with-workdir /src/hello |
  with-exec -- go build -o hello . |
  file ./hello |
  export ./hello-from-dagger
```

<VideoPlayer src="/img/current_docs/features/shell-build.webm" alt="Shell build example" />

## Bash frontend, Dagger backend

Dagger Shell uses the Bash syntax as a frontend, but its behavior is quite different in the backend:

- Instead of executing UNIX commands, you _execute Dagger Functions_
- Instead of passing text streams from command to command, you _pass typed objects from function to function_
- Instead of available commands being the same everywhere in the pipeline, _each command is executed in the context of the previous command's output object_. For example, `foo | bar` really means `foo().bar()`
- Instead of using the local host as an execution environment, you _use containerized runtimes_
- Instead of being mixed with regular commands, _shell builtins are prefixed with `.` (similar to SQLite)_

Besides these differences, **all the features** of the Bash *syntax* are available in Dagger Shell, including:

- Shell variables: `container=$(container | from alpine)`
- Shell functions: `container() { container | from alpine; }`
- Job control: `frontend | test & backend | test & .wait`
- Quoting: single quotes and double quotes have the same meaning as in bash

## Input modes

Dagger Shell supports multiple ways to input commands:

<Tabs groupId="shell">
<TabItem value="Inline execution">
```shell
dagger -c 'container | from alpine | terminal'
```
</TabItem>
<TabItem value="Standard input">
```shell title="First type 'dagger' for interactive mode."
dagger <<EOF
container | from alpine | terminal
EOF
```
</TabItem>
<TabItem value="Script">
```shell
#!/usr/bin/env dagger

container |
from alpine |
with-exec cat /etc/os-release |
stdout
```
</TabItem>
<TabItem value="Interactive REPL">
```shell title="First type 'dagger' for interactive mode."
container | from alpine | terminal
```
</TabItem>
</Tabs>

## Loading Modules

Dagger Shell can load [modules](/features/modules), inspect their types, and run their functions. This works for both local and remote modules.

<VideoPlayer src="/img/current_docs/features/shell-module.webm" alt="Dagger Shell module loading" />

For example, try running this command:

```shell
dagger -m github.com/dagger/dagger/docs@v0.18.5
```

This loads the module `github.com/dagger/dagger/docs` at version `v0.18.5`. Wait for the Dagger Shell interactive prompt, then:

```shell
.help
```

We see new commands available, loaded from the module. Let's try running one:

```shell
server | up
```

This builds the docs server defined in the module, and runs it as an ephemeral service [on your machine](http://localhost:8080).

## Composing modules

You can load multiple modules in the same session, each scoped to a single pipeline, then combine those pipelines into a bigger pipeline. For example:

```shell
dagger <<.
github.com/dagger/dagger/modules/wolfi |
 container --packages=nginx |
 with-directory /var/www $(
  github.com/dagger/dagger/docs | site
 )
.
```

This loads `github.com/dagger/dagger/docs` into one pipeline, `github.com/dagger/dagger/modules/wolfi` into another, then combines them.

This works by executing the module's [constructor function](/api/constructor/). It works exactly like executing any other function:

- You can inspect it for arguments: `.help MODULE`
- You can pass arguments: `MODULE --foo=bar --baz`
- You can save it to a variable: `foo=$(MODULE)`
- You can use it in a pipeline: `MODULE | foo | bar`
- You can use that pipeline as a sub-pipeline: `foo --bar=$(MODULE | foo | bar)`

## Variables

Dagger Shell lets you save the result of any command to a variable, using the standard bash syntax.
Values of any type can be saved to a variable, including objects.

Here's an example:

<Tabs groupId="shell">
<TabItem value="System shell">
```shell
dagger <<'.'
repo=$(git https://github.com/dagger/hello-dagger | head | tree)
env=$(container | from node:23 | with-directory /app $repo | with-workdir /app)
build=$($env | with-exec npm install | with-exec npm run build | directory ./dist)
container | from nginx | with-directory /usr/share/nginx/html $build | terminal --cmd=/bin/bash
.
```
</TabItem>
<TabItem value="Dagger Shell">
```shell title="First type 'dagger' for interactive mode."
repo=$(git https://github.com/dagger/hello-dagger | head | tree)
env=$(container | from node:23 | with-directory /app $repo | with-workdir /app)
build=$($env | with-exec npm install | with-exec npm run build | directory ./dist)
container | from nginx | with-directory /usr/share/nginx/html $build | terminal --cmd=/bin/bash
```
</TabItem>
</Tabs>

<VideoPlayer src="/img/current_docs/features/shell-variables.webm" alt="Dagger Shell variables" />

## Learn more

- [Call the Dagger API using Dagger Shell](../api/clients-cli.mdx)
- [Chain Dagger Functions using Dagger Shell](../api/chaining.mdx)
